﻿/*
 *	对象位置类2D版
 */
package labox.innovation.gameserver.model.actor.position;

import labox.innovation.config.Config;
import labox.innovation.gameserver.model.L2Object;
import labox.innovation.gameserver.model.Scene;
import labox.innovation.gameserver.model.SceneRegion;
import labox.innovation.gameserver.model.actor.knownlist.ObjectKnownList;
import labox.innovation.util.Point2D;

/**
 * 游戏基础对象位置处理类
 * 
 * @author Administrator
 * 
 */
public class ObjectPosition {

	protected L2Object _activeObject;

	private Point2D _worldPosition;

	private Scene _scene;

	private SceneRegion _sceneRegion; // 对象的位置区域：在世界中能被看到的道具/角色所使用

	// =========================================================
	// Constructor
	public ObjectPosition(L2Object activeObject) {
		_activeObject = activeObject;
		_worldPosition = new Point2D(0, 0);
	}

	public void setScene(Scene scene) {
		_scene = scene;
	}

	public Scene getScene() {
		return _scene;
	}

	public void setXY(int x, int y) {
		if (_scene == null)
			return;
		if (x > _scene.getWidth())
			x = _scene.getWidth();
		if (x < 0)
			x = 0;
		if (y > _scene.getHeight())
			y = _scene.getHeight();
		if (y < 0)
			y = 0;

		setScenePosition(x, y);

		if (_scene.getRegion(_worldPosition) != _sceneRegion)
			updateSceneRegion();
	}

	/**
	 * Called on setXYZ exception.<BR>
	 * <BR>
	 * <B><U> Overwritten in </U> :</B><BR>
	 * <BR>
	 * <li>CharPosition</li> <li>PcPosition</li><BR>
	 */
	protected void badCoords() {

	}

	/**
	 * Set the x,y position of the L2Object and make it invisible.<BR>
	 * <BR>
	 * 
	 * <B><U> Concept</U> :</B><BR>
	 * <BR>
	 * A L2Object is invisble if <B>_hidden</B>=true or <B>_worldregion</B>==null <BR>
	 * <BR>
	 * 
	 * <B><U> Assert </U> :</B><BR>
	 * <BR>
	 * <li>_worldregion==null <I>(L2Object is invisible)</I></li><BR>
	 * <BR>
	 * 
	 * <B><U> Example of use </U> :</B><BR>
	 * <BR>
	 * <li>Create a Door</li> <li>Restore L2PcInstance</li><BR>
	 */
	public final void setXYInvisible(int x, int y) {
		if (Config.ASSERT)
			assert _sceneRegion == null;

		setScenePosition(x, y);
		_activeObject.setIsVisible(false);
	}

	/**
	 * 根据玩家的XY坐标变化情况，更新region
	 */
	public void updateSceneRegion() {
		if (!_activeObject.isVisible())
			return;

		SceneRegion newRegion = _scene.getRegion(_worldPosition);
		if (newRegion != _sceneRegion) {
			_sceneRegion.removeVisibleObject(_activeObject);

			int startColumn, startRow, endColumn, endRow;

			int valueX = newRegion.get_tilex() - _sceneRegion.get_tilex();
			int valueY = newRegion.get_tiley() - _sceneRegion.get_tiley();

			if (valueX > 0) {
				startColumn = _sceneRegion.get_tilex() + 2;
				endColumn = newRegion.get_tilex() + 1;
				if (endColumn - startColumn > 2)
					startColumn = endColumn - 2;
				updataRegion(startColumn, newRegion.get_tiley() - 1, endColumn, newRegion.get_tiley() + 1);
			} else if (valueX < 0) {
				startColumn = newRegion.get_tilex() - 1;
				endColumn = _sceneRegion.get_tilex() - 2;
				if (endColumn - startColumn > 2)
					endColumn = startColumn + 2;
				updataRegion(startColumn, newRegion.get_tiley() - 1, endColumn, newRegion.get_tiley() + 1);
			}

			if (valueY > 0) {
				startRow = _sceneRegion.get_tiley() + 2;
				endRow = newRegion.get_tiley() + 1;
				if (endRow - startRow > 2)
					startRow = endRow - 2;
				if (valueX != 0) {
					if (valueX > 0) {
						updataRegion(newRegion.get_tilex() - 1, startRow, newRegion.get_tilex(), endRow);
					} else {
						updataRegion(newRegion.get_tilex(), startRow, newRegion.get_tilex() + 1, endRow);
					}
				} else
					updataRegion(newRegion.get_tilex() - 1, startRow, newRegion.get_tilex() + 1, endRow);
			} else if (valueY < 0) {
				startRow = newRegion.get_tiley() - 1;
				endRow = _sceneRegion.get_tiley() - 2;
				if (endRow - startRow > 2)
					endRow = startRow + 2;
				if (valueX != 0) {
					if (valueX > 0) {
						updataRegion(newRegion.get_tilex() - 1, startRow, newRegion.get_tilex(), endRow);
					} else {
						updataRegion(newRegion.get_tilex(), startRow, newRegion.get_tilex() + 1, endRow);
					}
				} else
					updataRegion(newRegion.get_tilex() - 1, startRow, newRegion.get_tilex() + 1, endRow);
			}

			_sceneRegion = newRegion;
			newRegion.addVisibleObject(_activeObject);
		}
	}

	// =========================================================
	// Method - Private

	// =========================================================
	// Property - Public
	public L2Object getActiveObject() {
		return _activeObject;
	}

	/** Return the x position of the L2Object. */
	public final int getX() {
		return _worldPosition.getX();
	}

	/** Return the y position of the L2Object. */
	public final int getY() {
		return _worldPosition.getY();
	}

	public final Point2D getScenePosition() {
		return _worldPosition;
	}

	public void setScenePosition(int x, int y) {
		_worldPosition.setXY(x, y);
	}

	public final void setScenePosition(Point2D newPosition) {
		setScenePosition(newPosition.getX(), newPosition.getY());
	}

	public final SceneRegion getSceneRegion() {
		return _sceneRegion;
	}

	public final void setSceneRegion(SceneRegion region) {
		_sceneRegion = region;
	}

	public void updataRegion(int startcolumn, int startrow, int endcolumn, int endrow) {
		ObjectKnownList regions = _activeObject.getKnownList();
		for (int i = startcolumn; i <= endcolumn; ++i) {
			for (int j = startrow; j <= endrow; ++j) {
				int column = i < 0 ? i + 3 : i;
				int row = j < 0 ? j + 3 : j;
				regions.addKnownRegion((row % 3) * 3 + (column % 3), _scene.getRegion(i, j));
			}
		}
	}
}
